package com.robertux.leaderboard.util.gestoresModelos;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;

import org.apache.log4j.Logger;
import org.jasypt.util.password.BasicPasswordEncryptor;

import com.robertux.leaderboard.beans.EstadoEntidad;
import com.robertux.leaderboard.beans.RolUsuario;
import com.robertux.leaderboard.beans.entities.Rol;
import com.robertux.leaderboard.beans.entities.SucursalSupervision;
import com.robertux.leaderboard.beans.entities.Usuario;

public class GestorUsuarios {
	private GestorEntidades<Usuario> gUsr;
	private GestorEntidades<Rol> gRol;
	private Logger logger;
	
	public GestorUsuarios() {
		this(new GestorEntidades<Usuario>());
	}
	
	public GestorUsuarios(GestorEntidades<Usuario> gestor) {
		this.gUsr = gestor;
		this.logger = Logger.getLogger(this.getClass());
		this.gRol = new GestorEntidades<Rol>();
	}
	
	public List<Usuario> getUsuarios() {
		TypedQuery<Usuario> qry = this.gUsr.getEntityManager().createQuery("SELECT u FROM Usuario u WHERE u.estado <> :estado", Usuario.class);
		qry.setParameter("estado", EstadoEntidad.ELIMINADO.getCodigo());
		
		try {
			return qry.getResultList();
		} catch (Exception e) {
			this.logger.error("Error tratando de consultar los usuarios: " + e.getMessage(), e);
			return new ArrayList<Usuario>();
		}
	}
	
	public List<Usuario> getUsuarios(int pagina, int filasPorPagina, String filtro) {
		TypedQuery<Usuario> qry = this.gUsr.getEntityManager().createQuery("SELECT u FROM Usuario u WHERE u.estado <> :estado" 
				+ (filtro != null && filtro.trim().length() > 0? " AND (UPPER(u.nombre) LIKE UPPER(:filtro) OR UPPER(u.usuario) LIKE UPPER(:filtro) OR UPPER(u.rol.nombre) LIKE UPPER(:filtro))": "") 
				+ " ORDER BY u.id", Usuario.class);
		
		qry.setParameter("estado", EstadoEntidad.ELIMINADO.getCodigo());
		if(filtro != null && filtro.trim().length() > 0) {
			qry.setParameter("filtro", "%" + filtro + "%");
		}
		qry.setFirstResult((pagina-1) * filasPorPagina);
		qry.setMaxResults(filasPorPagina);
		
		try {
			return qry.getResultList();
		} catch (Exception e) {
			this.logger.error("Error tratando de consultar los usuarios: " + e.getMessage(), e);
			return new ArrayList<Usuario>();
		}
	}
	
	public long getTotalUsuarios(String filtro) {
		TypedQuery<Long> qry = this.gUsr.getEntityManager().createQuery("SELECT count(u.id) FROM Usuario u WHERE u.estado <> :estado"
				+ (filtro != null && filtro.trim().length() > 0? " AND (UPPER(u.nombre) LIKE UPPER(:filtro) OR UPPER(u.usuario) LIKE UPPER(:filtro) OR UPPER(u.rol.nombre) LIKE UPPER(:filtro))": "")
				, Long.class);
		qry.setParameter("estado", EstadoEntidad.ELIMINADO.getCodigo());
		
		if(filtro != null && filtro.trim().length() > 0) {
			qry.setParameter("filtro", "%" + filtro + "%");
		}
		
		try {
			return qry.getSingleResult();
		} catch (NoResultException nrE) {
			return 0;
		} catch (Exception e) {
			this.logger.error("Error tratando de consultar el total de usuarios: " + e.getMessage(), e);
			return 0;
		}
	}
	
	public long getTotalUsuarios(int idSucursal, String filtro) {
		TypedQuery<Long> qry = this.gUsr.getEntityManager().createQuery("SELECT count(u.id) FROM Usuario u WHERE u.estado <> :estado AND u.sucursalId = :sucId"
				+ (filtro != null && filtro.trim().length() > 0? " AND (UPPER(u.nombre) LIKE UPPER(:filtro) OR UPPER(u.usuario) LIKE UPPER(:filtro) OR UPPER(u.rol.nombre) LIKE UPPER(:filtro))": "")
				, Long.class);
		
		qry.setParameter("estado", EstadoEntidad.ELIMINADO.getCodigo());
		qry.setParameter("sucId", idSucursal);
		
		if(filtro != null && filtro.trim().length() > 0) {
			qry.setParameter("filtro", "%" + filtro + "%");
		}
		
		try {
			return qry.getSingleResult();
		} catch (NoResultException nrE) {
			return 0;
		} catch (Exception e) {
			this.logger.error("Error tratando de consultar el total de usuarios: " + e.getMessage(), e);
			return 0;
		}
	}
	
	public List<Usuario> getUsuarios(int idSucursal) {
		TypedQuery<Usuario> qry = this.gUsr.getEntityManager().createQuery("SELECT u FROM Usuario u WHERE u.estado <> :estado AND u.sucursalId = :sucId ORDER BY u.id", Usuario.class);
		
		qry.setParameter("estado", EstadoEntidad.ELIMINADO.getCodigo());
		qry.setParameter("sucId", idSucursal);
		
		try {
			return qry.getResultList();
		} catch (Exception e) {
			this.logger.error("Error tratando de consultar los usuarios: " + e.getMessage(), e);
			return null;
		}
	}
	
	public List<Usuario> getUsuarios(int idSucursal, int pagina, int filasPorPagina, String filtro) {
		TypedQuery<Usuario> qry = this.gUsr.getEntityManager().createQuery("SELECT u FROM Usuario u WHERE u.estado <> :estado AND u.sucursalId = :sucId"
				+ (filtro != null && filtro.trim().length() > 0? " AND (UPPER(u.nombre) LIKE UPPER(:filtro) OR UPPER(u.usuario) LIKE UPPER(:filtro) OR UPPER(u.rol.nombre) LIKE UPPER(:filtro))": "")
				+ " ORDER BY u.id", Usuario.class);
		
		qry.setParameter("estado", EstadoEntidad.ELIMINADO.getCodigo());
		if(filtro != null && filtro.trim().length() > 0) {
			qry.setParameter("filtro", "%" + filtro + "%");
		}
		qry.setParameter("sucId", idSucursal);
		qry.setFirstResult((pagina-1) * filasPorPagina);
		qry.setMaxResults(filasPorPagina);
		
		try {
			return qry.getResultList();
		} catch (Exception e) {
			this.logger.error("Error tratando de consultar el usuario: " + e.getMessage(), e);
			return null;
		}
	}
	
	public List<Rol> getRoles() {
		return this.gRol.getEntidades("Rol", Rol.class);
	}
	
	public List<Usuario> getUsuarios(RolUsuario rol) {
		TypedQuery<Usuario> qry = this.gUsr.getEntityManager().createQuery("SELECT u FROM Usuario u WHERE u.rol.nivel = :rol", Usuario.class);
		qry.setParameter("rol", rol.getNivel());
		
		try {
			return qry.getResultList();
		} catch(Exception e) {
			this.logger.error("Error tratando de consultar los usuarios con rol " + rol + ": " + e.getMessage(), e);
			return null;
		}
	}
	
	public Usuario getUsuario(String usuario) {
		TypedQuery<Usuario> qry = this.gUsr.getEntityManager().createQuery("SELECT u FROM Usuario u WHERE u.usuario = :usuario", Usuario.class);
		qry.setParameter("usuario", usuario);
		
		try {
			return qry.getSingleResult();
		} catch (NoResultException nrE) {
			return null;
		} catch (Exception e) {
			this.logger.error("Error tratando de consultar el usuario: " + e.getMessage(), e);
			return null;
		}
	}
	
	public Usuario getUsuario(int userId) {
		return this.gUsr.getEntidad("Usuario", Usuario.class, userId);
	}
	
	public Rol getRol(int id) {
		try {
			return this.gRol.getEntidad("Rol", Rol.class, id);
		} catch (Exception e) {
			this.logger.error("No se pudo obtener un Rol con ID " + id + ": " + e.getMessage(), e);
			return null;
		}
	}
	
	public Usuario getUsuarioByIdVendedor(String idVendedor) {
		TypedQuery<Usuario> qry = this.gUsr.getEntityManager().createQuery("SELECT u FROM Usuario u WHERE u.vendedorId = :vendedorId", Usuario.class);
		qry.setParameter("vendedorId", idVendedor);
		
		try {
			return qry.getSingleResult();
		} catch (NoResultException nrE) {
			return null;
		} catch (Exception e) {
			this.logger.error("Error tratando de consultar el usuario: " + e.getMessage(), e);
			return null;
		}
	}
	
	public Usuario getUsuarioByIdEmpleado(String idEmpleado) {
		TypedQuery<Usuario> qry = this.gUsr.getEntityManager().createQuery("SELECT u FROM Usuario u WHERE u.empleadoId = :empleadoId", Usuario.class);
		qry.setParameter("empleadoId", idEmpleado);
		
		try {
			return qry.getSingleResult();
		} catch (NoResultException nrE) {
			return null;
		} catch (Exception e) {
			this.logger.error("Error tratando de consultar el usuario: " + e.getMessage(), e);
			return null;
		}
	}
	
	public Rol getRolFromLevel(int level) {
		TypedQuery<Rol> qry = this.gUsr.getEntityManager().createQuery("SELECT r FROM Rol r WHERE r.nivel = :nivel", Rol.class);
		qry.setParameter("nivel", level);
		
		try {
			return qry.getSingleResult();
		} catch (NoResultException nrE) {
			return null;
		} catch (Exception e) {
			this.logger.error("Error tratando de consultar el rol en base a su nivel: " + e.getMessage(), e);
			return null;
		}
	}
 	
	public boolean validarUsuario(String usuario, String clave) {
		boolean esValido = false;
		Usuario usr;
		
		try {
			if((usr = this.getUsuario(usuario)) != null) {
				BasicPasswordEncryptor bpe = new BasicPasswordEncryptor();
				esValido = bpe.checkPassword(clave, usr.getClave());
			}
		} catch (Exception e) {
			this.logger.error("Error tratando de validar el usuario: " + e.getMessage(), e);
		}
		
		return esValido;
	}
	
	public boolean agregarUsuario(Usuario usr) {
		boolean satisfactorio = false;
		
		try {
			BasicPasswordEncryptor encryptor = new BasicPasswordEncryptor();
			usr.setClave(encryptor.encryptPassword(usr.getClave()));
			this.gUsr.persistir(usr);
			satisfactorio = true;
		} catch (Exception e) {
			this.logger.error("Error tratando de persistir el usuario con la clave encriptada: " + e.getMessage(), e);
		}
		
		return satisfactorio;
	}
	
	public boolean cambiarClaveUsuario(Usuario usr, String claveAnterior, String nuevaClave) {
		boolean satisfactorio = false;
		
		BasicPasswordEncryptor bpe = new BasicPasswordEncryptor();
		if(bpe.checkPassword(claveAnterior, usr.getClave())) {
			usr.setClave(bpe.encryptPassword(nuevaClave));
			this.gUsr.actualizar(usr);
			satisfactorio = true;
		}
		return satisfactorio;
	}
	
	public boolean cambiarClaveUsuario(Usuario usr, String nuevaClave) {
		boolean satisfactorio = false;
		
		BasicPasswordEncryptor bpe = new BasicPasswordEncryptor();		
		usr.setClave(bpe.encryptPassword(nuevaClave));
		this.gUsr.actualizar(usr);
		satisfactorio = true;
		return satisfactorio;
	}
	
	public boolean validarClaveUsuario(Usuario usr, String clave) {
		return new BasicPasswordEncryptor().checkPassword(clave, usr.getClave());
	}

	public boolean actualizarUsuario(Usuario usr) {
		try {
			this.gUsr.actualizar(usr);
			return true;
		} catch (Exception e) {
			this.logger.error("Error tratando de actualizar el usuario: " + e.getMessage(), e);
			return false;
		}
	}
	
	public boolean eliminarUsuario(Usuario usr) {
		try {
			usr.setEstado(EstadoEntidad.ELIMINADO.getCodigo());
			this.gUsr.actualizar(usr);
			return true;
		} catch (Exception e) {
			this.logger.error("Error tratando de eliminar el usuario: " + e.getMessage(), e);
			return false;
		}
	}
	
	public boolean eliminarSucursalUsuario(SucursalSupervision suc) {
		try {
			this.gUsr.getEntityManager().getTransaction().begin();
			this.gUsr.getEntityManager().remove(this.gUsr.getEntityManager().merge(suc));
			this.gUsr.getEntityManager().getTransaction().commit();
			return true;
		} catch (Exception e) {
			this.logger.error("Error tratando de eliminar la sucursal asociada al usuario: " + e.getMessage(), e);
			return false;
		}
	}
}
